﻿// Copyright (c) 2012 - 2020 Jared Zheng <jaredz at outlook dot com>
// Buddha Framework is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Create : 2012-12-01 version 0.1 Jared Zheng <jaredz at outlook dot com>
// Update : 2018-12-05 version 3.1.5 Jared Zheng <jaredz at outlook dot com>

#ifndef __COMMON_PACKET_INL__
#define __COMMON_PACKET_INL__

#pragma once

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 会话
INLINE CPAKSessionBase::CPAKSessionBase(UEVENT uEvent, UTYPE uType, UACK uAck)
: CPAKHeadBase(uEvent, uType, uAck)
, m_ullSessionId(0)
{
}

INLINE CPAKSessionBase::~CPAKSessionBase(void)
{
}

INLINE CPAKSessionBase::CPAKSessionBase(const CPAKSessionBase& aSrc)
: CPAKHeadBase(aSrc)
, m_ullSessionId(aSrc.m_ullSessionId)
{
}

INLINE CPAKSessionBase& CPAKSessionBase::operator=(const CPAKSessionBase& aSrc)
{
    if (&aSrc != this)
    {
        CPAKHeadBase::operator=(aSrc);
        m_ullSessionId = aSrc.m_ullSessionId;
    }
    return (*this);
}

INLINE size_t CPAKSessionBase::Length(void)
{
    return (sizeof(ULLong) + CPAKHeadBase::Length());
}

INLINE void CPAKSessionBase::Serialize(CStream& Stream)
{
    CPAKHeadBase::Serialize(Stream);
    if (Stream.IsRead())
    {
        Stream >> m_ullSessionId;
    }
    else
    {
        Stream << m_ullSessionId;
    }
}

INLINE ULLong CPAKSessionBase::GetSessionId(void)
{
    return m_ullSessionId;
}

INLINE void CPAKSessionBase::SetSessionId(ULLong ullSessionId)
{
    m_ullSessionId = ullSessionId;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 会话模板
template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKSessionBase<uEvent, uType>::CTPAKSessionBase(UACK uAck)
: CTPAKHeadBase<uEvent, uType>(uAck)
, m_ullSessionId(0)
{
}

template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKSessionBase<uEvent, uType>::~CTPAKSessionBase(void)
{
}

template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKSessionBase<uEvent, uType>::CTPAKSessionBase(const CTPAKSessionBase<uEvent, uType>& aSrc)
: CTPAKHeadBase<uEvent, uType>(aSrc)
, m_ullSessionId(aSrc.m_ullSessionId)
{
}

template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKSessionBase<uEvent, uType>& CTPAKSessionBase<uEvent, uType>::operator=(const CTPAKSessionBase<uEvent, uType>& aSrc)
{
    if (&aSrc != this)
    {
        CTPAKHeadBase<uEvent, uType>::operator=(aSrc);
        m_ullSessionId = aSrc.m_ullSessionId;
    }
    return (*this);
}

template <UEVENT uEvent, UTYPE uType>
INLINE size_t CTPAKSessionBase<uEvent, uType>::Length(void)
{
    return (sizeof(ULLong) + CTPAKHeadBase<uEvent, uType>::Length());
}

template <UEVENT uEvent, UTYPE uType>
INLINE void CTPAKSessionBase<uEvent, uType>::Serialize(CStream& Stream)
{
    CTPAKHeadBase<uEvent, uType>::Serialize(Stream);
    if (Stream.IsRead())
    {
        Stream >> m_ullSessionId;
    }
    else
    {
        Stream << m_ullSessionId;
    }
}

template <UEVENT uEvent, UTYPE uType>
INLINE ULLong CTPAKSessionBase<uEvent, uType>::GetSessionId(void)
{
    return m_ullSessionId;
}

template <UEVENT uEvent, UTYPE uType>
INLINE void CTPAKSessionBase<uEvent, uType>::SetSessionId(ULLong ullSessionId)
{
    m_ullSessionId = ullSessionId;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 业务
INLINE CPAKRoutineBase::CPAKRoutineBase(UEVENT uEvent, UTYPE uType, UACK uAck)
: CPAKSessionBase(uEvent, uType, uAck)
, m_ullRoutineId(0)
{
}

INLINE CPAKRoutineBase::~CPAKRoutineBase(void)
{
}

INLINE CPAKRoutineBase::CPAKRoutineBase(const CPAKRoutineBase& aSrc)
: CPAKSessionBase(aSrc)
, m_ullRoutineId(aSrc.m_ullRoutineId)
{
}

INLINE CPAKRoutineBase& CPAKRoutineBase::operator=(const CPAKRoutineBase& aSrc)
{
    if (&aSrc != this)
    {
        CPAKSessionBase::operator=(aSrc);
        m_ullRoutineId  = aSrc.m_ullRoutineId;
    }
    return (*this);
}

INLINE size_t CPAKRoutineBase::Length(void)
{
    return (sizeof(ULLong) + CPAKSessionBase::Length());
}

INLINE void CPAKRoutineBase::Serialize(CStream& Stream)
{
    CPAKSessionBase::Serialize(Stream);
    if (Stream.IsRead())
    {
        Stream >> m_ullRoutineId;
    }
    else
    {
        Stream << m_ullRoutineId;
    }
}

INLINE ULLong CPAKRoutineBase::GetRoutineId(void)
{
    return m_ullRoutineId;
}

INLINE void CPAKRoutineBase::SetRoutineId(ULLong ullRoutineId)
{
    m_ullRoutineId = ullRoutineId;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 业务模板
template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKRoutineBase<uEvent, uType>::CTPAKRoutineBase(UACK uAck)
: CTPAKSessionBase<uEvent, uType>(uAck)
, m_ullRoutineId(0)
{
}

template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKRoutineBase<uEvent, uType>::~CTPAKRoutineBase(void)
{
}

template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKRoutineBase<uEvent, uType>::CTPAKRoutineBase(const CTPAKRoutineBase<uEvent, uType>& aSrc)
: CTPAKSessionBase<uEvent, uType>(aSrc)
, m_ullRoutineId(aSrc.m_ullRoutineId)
{
}

template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKRoutineBase<uEvent, uType>& CTPAKRoutineBase<uEvent, uType>::operator=(const CTPAKRoutineBase<uEvent, uType>& aSrc)
{
    if (&aSrc != this)
    {
        CTPAKSessionBase<uEvent, uType>::operator=(aSrc);
        m_ullRoutineId  = aSrc.m_ullRoutineId;
    }
    return (*this);
}

template <UEVENT uEvent, UTYPE uType>
INLINE size_t CTPAKRoutineBase<uEvent, uType>::Length(void)
{
    return (sizeof(ULLong) + CTPAKSessionBase<uEvent, uType>::Length());
}

template <UEVENT uEvent, UTYPE uType>
INLINE void CTPAKRoutineBase<uEvent, uType>::Serialize(CStream& Stream)
{
    CTPAKSessionBase<uEvent, uType>::Serialize(Stream);
    if (Stream.IsRead())
    {
        Stream >> m_ullRoutineId;
    }
    else
    {
        Stream << m_ullRoutineId;
    }
}

template <UEVENT uEvent, UTYPE uType>
INLINE ULLong CTPAKRoutineBase<uEvent, uType>::GetRoutineId(void)
{
    return m_ullRoutineId;
}

template <UEVENT uEvent, UTYPE uType>
INLINE void CTPAKRoutineBase<uEvent, uType>::SetRoutineId(ULLong ullRoutineId)
{
    m_ullRoutineId = ullRoutineId;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 通用数据流模板TPAKBase : CPAKHeadBase, CPAKSessionBase, CPAKRoutineBase或者继承类
template <typename TPAKBase>
INLINE CTPAKStream<TPAKBase>::CTPAKStream(UEVENT uEvent, UTYPE uType, UACK uAck)
: TPAKBase(uEvent, uType, uAck)
, m_pStream(nullptr)
{
#ifdef __RUNTIME_DEBUG__
    typename TConvertCheck<TPAKBase, CPAKHeadBase>::TAG tag = ConvertibleTag();
    tag.Check();
#endif
}

template <typename TPAKBase>
INLINE CTPAKStream<TPAKBase>::~CTPAKStream(void)
{
}

template <typename TPAKBase>
INLINE CTPAKStream<TPAKBase>::CTPAKStream(const CTPAKStream<TPAKBase>& aSrc)
: TPAKBase(aSrc)
, m_pStream(aSrc.m_pStream)
{
}

template <typename TPAKBase>
INLINE CTPAKStream<TPAKBase>& CTPAKStream<TPAKBase>::operator=(const CTPAKStream<TPAKBase>& aSrc)
{
    if (&aSrc != this)
    {
        TPAKBase::operator=(aSrc);
        m_pStream = aSrc.m_pStream;
    }
    return (*this);
}

template <typename TPAKBase>
INLINE size_t CTPAKStream<TPAKBase>::Length(void)
{
    return TPAKBase::Length();
}

template <typename TPAKBase>
INLINE void CTPAKStream<TPAKBase>::Serialize(CStream& Stream)
{
    TPAKBase::Serialize(Stream);
    if (Stream.IsRead())
    {
        SetStream(Stream);
    }
}

template <typename TPAKBase>
INLINE UInt CTPAKStream<TPAKBase>::GetStreamType(void)
{
    return PAK_STREAM_NONE;
}

template <typename TPAKBase>
INLINE bool CTPAKStream<TPAKBase>::CheckStream(void)
{
    return (m_pStream != nullptr);
}

template <typename TPAKBase>
INLINE CStream& CTPAKStream<TPAKBase>::GetStream(void)
{
    return (*m_pStream);
}

template <typename TPAKBase>
INLINE void CTPAKStream<TPAKBase>::SetStream(CStream& Stream)
{
    m_pStream = &Stream;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 通用数据流模板TPAKBase : CTPAKHeadBase, CTPAKSessionBase, CTPAKRoutineBase或者继承类
template <typename TPAKBaseT>
INLINE CTPAKStreamT<TPAKBaseT>::CTPAKStreamT(UACK uAck)
: TPAKBaseT(uAck)
, m_pStream(nullptr)
{
#ifdef __RUNTIME_DEBUG__
    typename TConvertCheck<TPAKBaseT, CPAKHeadBase>::TAG tag = ConvertibleTag();
    tag.Check();
#endif
}

template <typename TPAKBaseT>
INLINE CTPAKStreamT<TPAKBaseT>::~CTPAKStreamT(void)
{
}

template <typename TPAKBaseT>
INLINE CTPAKStreamT<TPAKBaseT>::CTPAKStreamT(const CTPAKStreamT<TPAKBaseT>& aSrc)
: TPAKBaseT(aSrc)
, m_pStream(aSrc.m_pStream)
{
}

template <typename TPAKBaseT>
INLINE CTPAKStreamT<TPAKBaseT>& CTPAKStreamT<TPAKBaseT>::operator=(const CTPAKStreamT<TPAKBaseT>& aSrc)
{
    if (&aSrc != this)
    {
        TPAKBaseT::operator=(aSrc);
        m_pStream = aSrc.m_pStream;
    }
    return (*this);
}

template <typename TPAKBaseT>
INLINE size_t CTPAKStreamT<TPAKBaseT>::Length(void)
{
    return TPAKBaseT::Length();
}

template <typename TPAKBaseT>
INLINE void CTPAKStreamT<TPAKBaseT>::Serialize(CStream& Stream)
{
    TPAKBaseT::Serialize(Stream);
    if (Stream.IsRead())
    {
        SetStream(Stream);
    }
}

template <typename TPAKBaseT>
INLINE UInt CTPAKStreamT<TPAKBaseT>::GetStreamType(void)
{
    return PAK_STREAM_NONE;
}

template <typename TPAKBaseT>
INLINE bool CTPAKStreamT<TPAKBaseT>::CheckStream(void)
{
    return (m_pStream != nullptr);
}

template <typename TPAKBaseT>
INLINE CStream& CTPAKStreamT<TPAKBaseT>::GetStream(void)
{
    return (*m_pStream);
}

template <typename TPAKBaseT>
INLINE void CTPAKStreamT<TPAKBaseT>::SetStream(CStream& Stream)
{
    m_pStream = &Stream;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// NET缓存数据流模板TPAKBase : CPAKHeadBase, CPAKSessionBase, CPAKRoutineBase或者继承类
template <typename TPAKBase>
INLINE CTPAKNETStream<TPAKBase>::CTPAKNETStream(UEVENT uEvent, UTYPE uType, UACK uAck)
: CTPAKStream<TPAKBase>(uEvent, uType, uAck)
, m_uStreamType(PAK_STREAM_ATTACH)
, m_uBaseSize(0)
, m_stCache(0)
, m_Index(nullptr)
, m_pCache(nullptr)
{
#ifdef __RUNTIME_DEBUG__
    typename TConvertCheck<TPAKBase, CPAKHeadBase>::TAG tag = ConvertibleTag();
    tag.Check();
#endif
    m_uBaseSize = (UInt)CTPAKStream<TPAKBase>::Length();
}

template <typename TPAKBase>
INLINE CTPAKNETStream<TPAKBase>::~CTPAKNETStream(void)
{
    Free();
}

template <typename TPAKBase>
INLINE CTPAKNETStream<TPAKBase>::CTPAKNETStream(const CTPAKNETStream<TPAKBase>& aSrc)
: CTPAKStream<TPAKBase>(aSrc)
, m_uStreamType(PAK_STREAM_ATTACH)
, m_uBaseSize(0)
, m_stCache(0)
, m_Index(nullptr)
, m_pCache(nullptr)
{
}

template <typename TPAKBase>
INLINE CTPAKNETStream<TPAKBase>& CTPAKNETStream<TPAKBase>::operator=(const CTPAKNETStream<TPAKBase>& aSrc)
{
    if (&aSrc != this)
    {
        CTPAKStream<TPAKBase>::operator=(aSrc);
        m_uStreamType = PAK_STREAM_ATTACH;
        m_uBaseSize   = 0;
        m_stCache     = 0;
        m_Index       = nullptr;
        m_pCache      = nullptr;
    }
    return (*this);
}

template <typename TPAKBase>
INLINE size_t CTPAKNETStream<TPAKBase>::Length(void)
{
    if (m_StreamPtr != nullptr)
    {
        return m_StreamPtr->Tell();
    }
    else if (m_BufRead.Size() > 0)
    {
        return m_BufRead.Size();
    }
    else
    {
        return CTPAKStream<TPAKBase>::Length();
    }
}

template <typename TPAKBase>
INLINE void CTPAKNETStream<TPAKBase>::Serialize(CStream& Stream)
{
    if (Stream.IsRead())
    {
        CTPAKStream<TPAKBase>::Serialize(Stream);
        SetStream(Stream);
    }
    else if (m_BufRead.Size() > 0)
    {
        Stream.Write(m_BufRead.GetBuf(), m_BufRead.Size());
    }
    else
    {
        CTPAKStream<TPAKBase>::Serialize(Stream);
    }
}

template <typename TPAKBase>
INLINE UInt CTPAKNETStream<TPAKBase>::GetStreamType(void)
{
    return m_uStreamType;
}

template <typename TPAKBase>
INLINE CBufStreamBase& CTPAKNETStream<TPAKBase>::Attach(ULLong ullParam, QUEUE_TYPE eType, CNetworkPtr& NetworkPtr)
{
    if (eType < QUEUE_TYPE_MASK)
    {
        return m_BufRead;
    }

    if ((m_Index == nullptr) && (m_pCache == nullptr))
    {
        Free();

        CNETTraits::PTCP_PARAM pTcp = reinterpret_cast<CNETTraits::PTCP_PARAM>(ullParam);
        if (eType & QUEUE_TYPE_UDP)
        {
            m_NetAddr = ((CNETTraits::PUDP_PARAM)pTcp)->NetAddr;
        }
        m_stCache = pTcp->stCache;
        m_Index   = pTcp->index;
        m_pCache  = pTcp->pCache;
        if (m_Index != nullptr)
        {
            m_BufRead.Attach(pTcp->stSize, pTcp->pData);
            m_BufRead.Seek((SeekPos)m_uBaseSize);
            SetStream(m_BufRead);

            pTcp->pData = nullptr;
        }
        else
        {
            if (Alloc(pTcp->pData, pTcp->stSize, NetworkPtr, (pTcp->stCache != 0)))
            {
                return (*m_ReferPtr);
            }
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStream<TPAKBase>::Attach m_Index=%p---m_pCache=%p is not nullptr"), m_Index, m_pCache);
    }
    return m_BufRead;
}

template <typename TPAKBase>
INLINE PByte CTPAKNETStream<TPAKBase>::Detach(PINDEX& index)
{
    if (m_uStreamType == PAK_STREAM_ATTACH)
    {
        PByte pCache = m_pCache;
        m_pCache = nullptr;

        index = m_Index;
        m_Index = nullptr;

        Free();
        return pCache;
    }
    return nullptr;
}

template <typename TPAKBase>
INLINE CBufStreamBase& CTPAKNETStream<TPAKBase>::Alloc(CNetworkPtr& NetworkPtr, bool bJumbo)
{
    Free();
    if (bJumbo)
    {
        NetworkPtr->AllocJumboBuffer(m_StreamPtr);
    }
    else
    {
        NetworkPtr->AllocBuffer(m_StreamPtr);
    }
    if (m_StreamPtr != nullptr)
    {
        m_stCache = m_StreamPtr->Size();
        m_StreamPtr->Seek((SeekPos)m_uBaseSize);

        m_uStreamType = PAK_STREAM_ALLOC;
        return (*m_StreamPtr);
    }
    return m_BufRead;
}

template <typename TPAKBase>
INLINE CBufStreamBase& CTPAKNETStream<TPAKBase>::WriteStream(CNetworkPtr& NetworkPtr, SeekPos sPos)
{
    if (m_StreamPtr != nullptr)
    {
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        return (*m_StreamPtr);
    }

    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            if (sPos == 0)
            {
                sPos = (SeekPos)m_uBaseSize;
            }
            m_StreamPtr->Seek(sPos);
            return (*m_StreamPtr);
        }
    }
    return m_BufRead;
}

template <typename TPAKBase>
INLINE CBufStreamBase& CTPAKNETStream<TPAKBase>::ReadStream(CNetworkPtr& NetworkPtr, SeekPos sPos)
{
    if (m_ReferPtr != nullptr)
    {
        m_ReferPtr = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        NetworkPtr->ReferBuffer(m_ReferPtr, m_StreamPtr);
        if (m_ReferPtr != nullptr)
        {
            if (sPos == 0)
            {
                sPos = (SeekPos)m_uBaseSize;
            }
            m_ReferPtr->Seek(sPos);
            return (*m_ReferPtr);
        }
    }

    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_BufRead.Seek(sPos);
    }
    return m_BufRead;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::Reset(SeekPos sPos)
{
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStream<TPAKBase>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        return true;
    }
    else if (m_BufRead.Size() > 0)
    {
        CBufWriteStream bws(m_BufRead.Size(), m_BufRead.GetBuf());
        CTPAKStream<TPAKBase>::Serialize(bws);
        return true;
    }
    return false;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::Send(Socket_t sSocket, CNetworkPtr& NetworkPtr, bool bClose)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            m_StreamPtr->Seek((SeekPos)m_uBaseSize);
        }
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStream<TPAKBase>::Serialize(*m_StreamPtr);
        }
        if (m_NetAddr.IsValid() == false)
        {
            return NetworkPtr->Send(sSocket, m_StreamPtr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
        else
        {
            return NetworkPtr->SendTo(sSocket, m_StreamPtr, m_NetAddr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStream<TPAKBase>::Send %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::SendCopy(Socket_t sSocket, CNetworkPtr& NetworkPtr, bool bClose)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            m_StreamPtr->Seek((SeekPos)m_uBaseSize);
        }
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStream<TPAKBase>::Serialize(*m_StreamPtr);
        }
        if (m_NetAddr.IsValid() == false)
        {
            return NetworkPtr->SendCopy(sSocket, m_StreamPtr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
        else
        {
            return NetworkPtr->SendToCopy(sSocket, m_StreamPtr, m_NetAddr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStream<TPAKBase>::SendCopy %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::ResetSend(Socket_t sSocket, CNetworkPtr& NetworkPtr, SeekPos sPos, bool bClose)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStream<TPAKBase>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        if (m_NetAddr.IsValid() == false)
        {
            return NetworkPtr->Send(sSocket, m_StreamPtr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
        else
        {
            return NetworkPtr->SendTo(sSocket, m_StreamPtr, m_NetAddr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStream<TPAKBase>::ResetSend %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::ResetSendCopy(Socket_t sSocket, CNetworkPtr& NetworkPtr, SeekPos sPos, bool bClose)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStream<TPAKBase>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        if (m_NetAddr.IsValid() == false)
        {
            return NetworkPtr->SendCopy(sSocket, m_StreamPtr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
        else
        {
            return NetworkPtr->SendToCopy(sSocket, m_StreamPtr, m_NetAddr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStream<TPAKBase>::ResetSendCopy %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::BroadcastSend(CNetworkPtr& NetworkPtr, Int nFlag, ULLong ullParam)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            m_StreamPtr->Seek((SeekPos)m_uBaseSize);
        }
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStream<TPAKBase>::Serialize(*m_StreamPtr);
        }
        return NetworkPtr->Send(0, m_StreamPtr, nFlag, ullParam);
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStream<TPAKBase>::BroadcastSend %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::BroadcastSendCopy(CNetworkPtr& NetworkPtr, Int nFlag, ULLong ullParam)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            m_StreamPtr->Seek((SeekPos)m_uBaseSize);
        }
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStream<TPAKBase>::Serialize(*m_StreamPtr);
        }
        return NetworkPtr->SendCopy(0, m_StreamPtr, nFlag, ullParam);
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStream<TPAKBase>::BroadcastSendCopy %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::ResetBroadcastSend(CNetworkPtr& NetworkPtr, SeekPos sPos, Int nFlag, ULLong ullParam)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStream<TPAKBase>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        return NetworkPtr->Send(0, m_StreamPtr, nFlag, ullParam);
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStream<TPAKBase>::ResetBroadcastSend %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::ResetBroadcastSendCopy(CNetworkPtr& NetworkPtr, SeekPos sPos, Int nFlag, ULLong ullParam)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStream<TPAKBase>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        return NetworkPtr->SendCopy(0, m_StreamPtr, nFlag, ullParam);
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStream<TPAKBase>::ResetBroadcastSendCopy %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBase>
INLINE size_t CTPAKNETStream<TPAKBase>::BaseSize(void)
{
    return m_uBaseSize;
}

template <typename TPAKBase>
INLINE size_t CTPAKNETStream<TPAKBase>::Cache(bool bValid)
{
    if (m_stCache > 0)
    {
        if (bValid)
        {
            return (m_stCache - (size_t)m_uBaseSize);
        }
        else
        {
            return m_stCache;
        }
    }
    return 0;
}

template <typename TPAKBase>
INLINE CNetAddr& CTPAKNETStream<TPAKBase>::Addr(void)
{
    return m_NetAddr;
}

template <typename TPAKBase>
INLINE void CTPAKNETStream<TPAKBase>::Addr(CNetAddr& SetAddr)
{
    m_NetAddr = SetAddr;
}

template <typename TPAKBase>
INLINE void CTPAKNETStream<TPAKBase>::Free(void)
{
    m_BufRead.Close();
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        MObject::MCFree(m_Index, m_pCache);
    }
    m_Index   = nullptr;
    m_pCache  = nullptr;
    m_stCache = 0;

    m_NetAddr.Reset();

    if (m_ReferPtr != nullptr)
    {
        m_ReferPtr = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        m_StreamPtr = nullptr;
    }

    m_uStreamType = PAK_STREAM_ATTACH;
}

template <typename TPAKBase>
INLINE bool CTPAKNETStream<TPAKBase>::Alloc(PByte pData, size_t stSize, CNetworkPtr& NetworkPtr, bool bJumbo)
{
    if (bJumbo)
    {
        NetworkPtr->AllocJumboBuffer(m_StreamPtr);
    }
    else
    {
        NetworkPtr->AllocBuffer(m_StreamPtr);
    }
    if (m_StreamPtr != nullptr)
    {
        DEV_DUMP(TF("CTPAKNETStream<TPAKBase>::Alloc %d---%d Cache Size=%d, Data Size=%d"), GetEvent(), bJumbo, m_StreamPtr->Size(), stSize);
        m_stCache = m_StreamPtr->Size();
        m_StreamPtr->Write(pData, stSize);
        m_StreamPtr->Seek(stSize);

        m_uStreamType = PAK_STREAM_ALLOC;

        NetworkPtr->ReferBuffer(m_ReferPtr, m_StreamPtr);
        if (m_ReferPtr != nullptr)
        {
            m_ReferPtr->Seek((SeekPos)m_uBaseSize);
            SetStream(*m_ReferPtr);
            return true;
        }
    }
    return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// NET缓存数据流模板TPAKBaseT : CTPAKHeadBase, CTPAKSessionBase, CTPAKRoutineBase或者继承类
template <typename TPAKBaseT>
INLINE CTPAKNETStreamT<TPAKBaseT>::CTPAKNETStreamT(UACK uAck)
: CTPAKStreamT<TPAKBaseT>(uAck)
, m_uStreamType(PAK_STREAM_ATTACH)
, m_uBaseSize(0)
, m_stCache(0)
, m_Index(nullptr)
, m_pCache(nullptr)
{
#ifdef __RUNTIME_DEBUG__
    typename TConvertCheck<TPAKBaseT, CPAKHeadBase>::TAG tag = ConvertibleTag();
    tag.Check();
#endif
    m_uBaseSize = (UInt)CTPAKStreamT<TPAKBaseT>::Length();
}

template <typename TPAKBaseT>
INLINE CTPAKNETStreamT<TPAKBaseT>::~CTPAKNETStreamT(void)
{
    Free();
}

template <typename TPAKBaseT>
INLINE CTPAKNETStreamT<TPAKBaseT>::CTPAKNETStreamT(const CTPAKNETStreamT<TPAKBaseT>& aSrc)
: CTPAKStreamT<TPAKBaseT>(aSrc)
, m_uStreamType(PAK_STREAM_ATTACH)
, m_uBaseSize(0)
, m_stCache(0)
, m_Index(nullptr)
, m_pCache(nullptr)
{
}

template <typename TPAKBaseT>
INLINE CTPAKNETStreamT<TPAKBaseT>& CTPAKNETStreamT<TPAKBaseT>::operator=(const CTPAKNETStreamT<TPAKBaseT>& aSrc)
{
    if (&aSrc != this)
    {
        CTPAKStreamT<TPAKBaseT>::operator=(aSrc);
        m_uStreamType = PAK_STREAM_ATTACH;
        m_uBaseSize   = 0;
        m_stCache     = 0;
        m_Index       = nullptr;
        m_pCache      = nullptr;
    }
    return (*this);
}

template <typename TPAKBaseT>
INLINE size_t CTPAKNETStreamT<TPAKBaseT>::Length(void)
{
    if (m_StreamPtr != nullptr)
    {
        return m_StreamPtr->Tell();
    }
    else if (m_BufRead.Size() > 0)
    {
        return m_BufRead.Size();
    }
    else
    {
        return CTPAKStreamT<TPAKBaseT>::Length();
    }
}

template <typename TPAKBaseT>
INLINE void CTPAKNETStreamT<TPAKBaseT>::Serialize(CStream& Stream)
{
    if (Stream.IsRead())
    {
        CTPAKStreamT<TPAKBaseT>::Serialize(Stream);
        SetStream(Stream);
    }
    else if (m_BufRead.Size() > 0)
    {
        Stream.Write(m_BufRead.GetBuf(), m_BufRead.Size());
    }
    else
    {
        CTPAKStreamT<TPAKBaseT>::Serialize(Stream);
    }
}

template <typename TPAKBaseT>
INLINE UInt CTPAKNETStreamT<TPAKBaseT>::GetStreamType(void)
{
    return m_uStreamType;
}

template <typename TPAKBaseT>
INLINE CBufStreamBase& CTPAKNETStreamT<TPAKBaseT>::Attach(ULLong ullParam, QUEUE_TYPE eType, CNetworkPtr& NetworkPtr)
{
    if (eType < QUEUE_TYPE_MASK)
    {
        return m_BufRead;
    }

    if ((m_Index == nullptr) && (m_pCache == nullptr))
    {
        Free();

        CNETTraits::PTCP_PARAM pTcp = reinterpret_cast<CNETTraits::PTCP_PARAM>(ullParam);
        if (eType & QUEUE_TYPE_UDP)
        {
            m_NetAddr = ((CNETTraits::PUDP_PARAM)pTcp)->NetAddr;
        }
        m_stCache = pTcp->stCache;
        m_Index   = pTcp->index;
        m_pCache  = pTcp->pCache;
        if (m_Index != nullptr)
        {
            m_BufRead.Attach(pTcp->stSize, pTcp->pData);
            m_BufRead.Seek((SeekPos)m_uBaseSize);
            SetStream(m_BufRead);

            pTcp->pData = nullptr;
        }
        else
        {
            if (Alloc(pTcp->pData, pTcp->stSize, NetworkPtr, (pTcp->stCache != 0)))
            {
                return (*m_ReferPtr);
            }
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStreamT<TPAKBaseT>::Attach m_Index=%p---m_pCache=%p is not nullptr"), m_Index, m_pCache);
    }
    return m_BufRead;
}

template <typename TPAKBaseT>
INLINE PByte CTPAKNETStreamT<TPAKBaseT>::Detach(PINDEX& index)
{
    if (m_uStreamType == PAK_STREAM_ATTACH)
    {
        PByte pCache = m_pCache;
        m_pCache = nullptr;

        index = m_Index;
        m_Index = nullptr;

        Free();
        return pCache;
    }
    return nullptr;
}

template <typename TPAKBaseT>
INLINE CBufStreamBase& CTPAKNETStreamT<TPAKBaseT>::Alloc(CNetworkPtr& NetworkPtr, bool bJumbo)
{
    Free();
    if (bJumbo)
    {
        NetworkPtr->AllocJumboBuffer(m_StreamPtr);
    }
    else
    {
        NetworkPtr->AllocBuffer(m_StreamPtr);
    }
    if (m_StreamPtr != nullptr)
    {
        m_stCache = m_StreamPtr->Size();
        m_StreamPtr->Seek((SeekPos)m_uBaseSize);

        m_uStreamType = PAK_STREAM_ALLOC;
        return (*m_StreamPtr);
    }
    return m_BufRead;
}

template <typename TPAKBaseT>
INLINE CBufStreamBase& CTPAKNETStreamT<TPAKBaseT>::WriteStream(CNetworkPtr& NetworkPtr, SeekPos sPos)
{
    if (m_StreamPtr != nullptr)
    {
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        return (*m_StreamPtr);
    }

    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            if (sPos == 0)
            {
                sPos = (SeekPos)m_uBaseSize;
            }
            m_StreamPtr->Seek(sPos);
            return (*m_StreamPtr);
        }
    }
    return m_BufRead;
}

template <typename TPAKBaseT>
INLINE CBufStreamBase& CTPAKNETStreamT<TPAKBaseT>::ReadStream(CNetworkPtr& NetworkPtr, SeekPos sPos)
{
    if (m_ReferPtr != nullptr)
    {
        m_ReferPtr = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        NetworkPtr->ReferBuffer(m_ReferPtr, m_StreamPtr);
        if (m_ReferPtr != nullptr)
        {
            if (sPos == 0)
            {
                sPos = (SeekPos)m_uBaseSize;
            }
            m_ReferPtr->Seek(sPos);
            return (*m_ReferPtr);
        }
    }

    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_BufRead.Seek(sPos);
    }
    return m_BufRead;
}


template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::Reset(SeekPos sPos)
{
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStreamT<TPAKBaseT>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        return true;
    }
    else if (m_BufRead.Size() > 0)
    {
        CBufWriteStream bws(m_BufRead.Size(), m_BufRead.GetBuf());
        CTPAKStreamT<TPAKBaseT>::Serialize(bws);
        return true;
    }
    return false;
}

template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::Send(Socket_t sSocket, CNetworkPtr& NetworkPtr, bool bClose)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            m_StreamPtr->Seek((SeekPos)m_uBaseSize);
        }
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStreamT<TPAKBaseT>::Serialize(*m_StreamPtr);
        }
        if (m_NetAddr.IsValid() == false)
        {
            return NetworkPtr->Send(sSocket, m_StreamPtr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
        else
        {
            return NetworkPtr->SendTo(sSocket, m_StreamPtr, m_NetAddr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStreamT<TPAKBaseT>::Send %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::SendCopy(Socket_t sSocket, CNetworkPtr& NetworkPtr, bool bClose)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            m_StreamPtr->Seek((SeekPos)m_uBaseSize);
        }
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStreamT<TPAKBaseT>::Serialize(*m_StreamPtr);
        }
        if (m_NetAddr.IsValid() == false)
        {
            return NetworkPtr->SendCopy(sSocket, m_StreamPtr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
        else
        {
            return NetworkPtr->SendToCopy(sSocket, m_StreamPtr, m_NetAddr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStreamT<TPAKBaseT>::SendCopy %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::ResetSend(Socket_t sSocket, CNetworkPtr& NetworkPtr, SeekPos sPos, bool bClose)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStreamT<TPAKBaseT>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        if (m_NetAddr.IsValid() == false)
        {
            return NetworkPtr->Send(sSocket, m_StreamPtr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
        else
        {
            return NetworkPtr->SendTo(sSocket, m_StreamPtr, m_NetAddr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStreamT<TPAKBaseT>::ResetSend %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::ResetSendCopy(Socket_t sSocket, CNetworkPtr& NetworkPtr, SeekPos sPos, bool bClose)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStreamT<TPAKBaseT>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        if (m_NetAddr.IsValid() == false)
        {
            return NetworkPtr->SendCopy(sSocket, m_StreamPtr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
        else
        {
            return NetworkPtr->SendToCopy(sSocket, m_StreamPtr, m_NetAddr, bClose ? CNETTraits::SEND_CLOSE : CNETTraits::SEND_NORMAL);
        }
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStreamT<TPAKBaseT>::ResetSendCopy %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::BroadcastSend(CNetworkPtr& NetworkPtr, Int nFlag, ULLong ullParam)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            m_StreamPtr->Seek((SeekPos)m_uBaseSize);
        }
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStreamT<TPAKBaseT>::Serialize(*m_StreamPtr);
        }
        return NetworkPtr->Send(0, m_StreamPtr, nFlag, ullParam);
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStreamT<TPAKBaseT>::BroadcastSend %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::BroadcastSendCopy(CNetworkPtr& NetworkPtr, Int nFlag, ULLong ullParam)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
        if (m_StreamPtr != nullptr)
        {
            m_StreamPtr->Seek((SeekPos)m_uBaseSize);
        }
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStreamT<TPAKBaseT>::Serialize(*m_StreamPtr);
        }
        return NetworkPtr->SendCopy(0, m_StreamPtr, nFlag, ullParam);
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStreamT<TPAKBaseT>::BroadcastSendCopy %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::ResetBroadcastSend(CNetworkPtr& NetworkPtr, SeekPos sPos, Int nFlag, ULLong ullParam)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStreamT<TPAKBaseT>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        return NetworkPtr->Send(0, m_StreamPtr, nFlag, ullParam);
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStreamT<TPAKBaseT>::ResetBroadcastSend %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::ResetBroadcastSendCopy(CNetworkPtr& NetworkPtr, SeekPos sPos, Int nFlag, ULLong ullParam)
{
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        // 没有生成写数据流, 表示没有额外数据
        NetworkPtr->ReuseBuffer(m_StreamPtr, m_Index, m_pCache);
        m_Index  = nullptr;
        m_pCache = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        {
            CStreamSeekScope scope(*m_StreamPtr, 0);
            CTPAKStreamT<TPAKBaseT>::Serialize(*m_StreamPtr);
        }
        if (sPos == 0)
        {
            sPos = (SeekPos)m_uBaseSize;
        }
        m_StreamPtr->Seek(sPos);
        return NetworkPtr->SendCopy(0, m_StreamPtr, nFlag, ullParam);
    }
    else
    {
        DEV_ERROR(TF("CTPAKNETStreamT<TPAKBaseT>::ResetBroadcastSendCopy %d m_Index=%p---m_pCache=%p Failed[%d---%d---%d]"), GetEvent(), m_Index, m_pCache, m_uStreamType, m_uBaseSize, m_stCache);
    }
    return false;
}

template <typename TPAKBaseT>
INLINE size_t CTPAKNETStreamT<TPAKBaseT>::BaseSize(void)
{
    return m_uBaseSize;
}

template <typename TPAKBaseT>
INLINE size_t CTPAKNETStreamT<TPAKBaseT>::Cache(bool bValid)
{
    if (m_stCache > 0)
    {
        if (bValid)
        {
            return (m_stCache - (size_t)m_uBaseSize);
        }
        else
        {
            return m_stCache;
        }
    }
    return 0;
}

template <typename TPAKBaseT>
INLINE CNetAddr& CTPAKNETStreamT<TPAKBaseT>::Addr(void)
{
    return m_NetAddr;
}

template <typename TPAKBaseT>
INLINE void CTPAKNETStreamT<TPAKBaseT>::Addr(CNetAddr& SetAddr)
{
    m_NetAddr = SetAddr;
}

template <typename TPAKBaseT>
INLINE void CTPAKNETStreamT<TPAKBaseT>::Free(void)
{
    m_BufRead.Close();
    if ((m_Index != nullptr) && (m_pCache != nullptr))
    {
        MObject::MCFree(m_Index, m_pCache);
    }
    m_Index   = nullptr;
    m_pCache  = nullptr;
    m_stCache = 0;

    m_NetAddr.Reset();

    if (m_ReferPtr != nullptr)
    {
        m_ReferPtr = nullptr;
    }
    if (m_StreamPtr != nullptr)
    {
        m_StreamPtr = nullptr;
    }

    m_uStreamType = PAK_STREAM_ATTACH;
}

template <typename TPAKBaseT>
INLINE bool CTPAKNETStreamT<TPAKBaseT>::Alloc(PByte pData, size_t stSize, CNetworkPtr& NetworkPtr, bool bJumbo)
{
    if (bJumbo)
    {
        NetworkPtr->AllocJumboBuffer(m_StreamPtr);
    }
    else
    {
        NetworkPtr->AllocBuffer(m_StreamPtr);
    }
    if (m_StreamPtr != nullptr)
    {
        DEV_DUMP(TF("CTPAKNETStreamT<TPAKBaseT>::Alloc %d---%d Cache Size=%d, Data Size=%d"), GetEvent(), bJumbo, m_StreamPtr->Size(), stSize);
        m_stCache = m_StreamPtr->Size();
        m_StreamPtr->Write(pData, stSize);
        m_StreamPtr->Seek(stSize);

        m_uStreamType = PAK_STREAM_ALLOC;

        NetworkPtr->ReferBuffer(m_ReferPtr, m_StreamPtr);
        if (m_ReferPtr != nullptr)
        {
            m_ReferPtr->Seek((SeekPos)m_uBaseSize);
            SetStream(*m_ReferPtr);
            return true;
        }
    }
    return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 服务器状态数据包
template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKServerStatusT<uEvent, uType>::CTPAKServerStatusT(UACK uAck)
: CTPAKHeadBase<uEvent, uType>(uAck)
{
    MM_SAFE::Set(&m_ServerStatus, 0, sizeof(SERVER_STATUS));
}

template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKServerStatusT<uEvent, uType>::~CTPAKServerStatusT(void)
{
}

template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKServerStatusT<uEvent, uType>::CTPAKServerStatusT(const CTPAKServerStatusT<uEvent, uType>& aSrc)
: CTPAKHeadBase<uEvent, uType>(aSrc)
{
    m_ServerStatus = aSrc.m_ServerStatus;
}

template <UEVENT uEvent, UTYPE uType>
INLINE CTPAKServerStatusT<uEvent, uType>& CTPAKServerStatusT<uEvent, uType>::operator=(const CTPAKServerStatusT<uEvent, uType>& aSrc)
{
    if (&aSrc != this)
    {
        CTPAKHeadBase<uEvent, uType>::operator=(aSrc);
        m_ServerStatus = aSrc.m_ServerStatus;
    }
    return (*this);
}

template <UEVENT uEvent, UTYPE uType>
INLINE size_t CTPAKServerStatusT<uEvent, uType>::Length(void)
{
    return (sizeof(SERVER_STATUS) + CTPAKHeadBase<uEvent, uType>::Length());
}

template <UEVENT uEvent, UTYPE uType>
INLINE void CTPAKServerStatusT<uEvent, uType>::Serialize(CStream& Stream)
{
    CTPAKHeadBase<uEvent, uType>::Serialize(Stream);
    if (Stream.IsRead())
    {
        Stream.Read(&m_ServerStatus, sizeof(SERVER_STATUS));
    }
    else
    {
        Stream.Write(&m_ServerStatus, sizeof(SERVER_STATUS));
    }
}

template <UEVENT uEvent, UTYPE uType>
INLINE SERVER_STATUS& CTPAKServerStatusT<uEvent, uType>::GetServerStatus(void)
{
    return m_ServerStatus;
}

template <UEVENT uEvent, UTYPE uType>
INLINE void CTPAKServerStatusT<uEvent, uType>::SetServerStatus(SERVER_STATUS& ss)
{
    m_ServerStatus = ss;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace CommonPack  : 通用包解析
INLINE CPAKHeadBase* CommonPack::Create(CStream& Stream, UEVENT& uEvent)
{
    CStreamSeekScope scope(Stream);
    CPAKHeadBase* pPak = nullptr;

    uEvent = 0;
    Stream >> uEvent;
    switch (uEvent)
    {
    // common
    case PAKE_LINK:
        {
            pPak = MNEW CNETLink;
        }
        break;
    case PAKE_UPDATE:
        {
            pPak = MNEW CNETUpdate;
        }
        break;
    case PAKE_SYNC:
        {
            pPak = MNEW CNETSync;
        }
        break;
    case PAKE_LIVE:
    case PAKE_LIVEACK:
    case PAKE_LINKACK:
    case PAKE_UPDATEACK:
    case PAKE_SYNCACK:
    case PAKE_UNLINK:
    case PAKE_UNLINKACK:
        {
            pPak = MNEW CPAKHeadBase(uEvent);
        }
        break;
    default:
        {
            if ((uEvent >= PAKE_COMMON_BEGIN) && (uEvent <= PAKE_COMMON_END))
            {
                pPak = MNEW CNETHead(uEvent);
            }
        }
    }
    return pPak;
}

INLINE size_t CommonPack::StringLen(CString& str)
{
    return (sizeof(UInt) + str.Length(true));
}

INLINE bool CommonPack::ReadString(CStream& Stream, CString& str, UInt uMaxLen)
{
    assert(Stream.IsRead());
    UInt uLen = 0;
    Stream >> uLen;
    if (uLen >= uMaxLen)
    {
        return false;
    }
    Stream >> str;
    if (str.Length() != uLen)
    {
        str.Empty();
        return false;
    }
    return true;
}

INLINE void CommonPack::WriteString(CStream& Stream, CString& str)
{
    assert(Stream.IsWrite());
    Stream << (UInt)str.Length() << str;
}

INLINE void CommonPack::WriteString(CStream& Stream, PCXStr psz)
{
    assert(Stream.IsWrite());
    Stream << (UInt)CXChar::Length(psz) << psz;
}

#endif // __COMMON_PACKET_INL__
